package com.example.lib_router_compiler.ksp.compiler

import com.example.lib_router_anntation.Module
import com.example.lib_router_anntation.RouterServiceData
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy


@OptIn(ExperimentalStdlibApi::class)
internal class Generator(
    private val packageName: String,
    private val className: String,
    private val routerPathMap: Map<String, String>,
    private val routerServiceMap: Map<String, String>,
    private val routerServiceImplMap: Map<String, RouterServiceImplInfo>
) {
    private val moduleClass = Module::class.asClassName()

    private val mapClass = typeNameOf<HashMap<String, Class<*>>>()
    private val mapDataClass = HashMap::class.asClassName().parameterizedBy(String::class.asClassName(), RouterServiceData::class.asClassName())

    fun generate(): FileSpec {
        val companion = TypeSpec.companionObjectBuilder()
            .addFunction(
                FunSpec.builder("doNothing")
                    .returns(moduleClass)
                    .addStatement("return ${className}()")
                    .build()
            )
            .build()
        val classBuilder = TypeSpec.classBuilder(className)
            .addSuperinterface(moduleClass)
            .primaryConstructor(FunSpec.constructorBuilder().build())
            .addProperty(
                PropertySpec.builder("routerPathMap", mapClass)
                    .initializer("hashMapOf<String,  Class<*>>()")
                    .build()
            )
            .addProperty(
                PropertySpec.builder("routerServiceMap", mapClass)
                    .initializer("hashMapOf<String, Class<*>>()")
                    .build()
            )
            .addProperty(
                PropertySpec.builder("routerServiceImplMap", mapDataClass)
                    .initializer("hashMapOf<String, RouterServiceData>()")
                    .build()
            )
            .addInitializerBlock(
                generateRouterPathMapBlock()
            )
            .addInitializerBlock(
                generateRouterServiceMapBlock()
            )
            .addInitializerBlock(
                generateRouterServiceImplMapBlock()
            )
            .addFunction(
                FunSpec.builder("getRouterPath")
                    .addModifiers(KModifier.OVERRIDE)
                    .addStatement("return routerPathMap")
                    .returns(mapClass)
                    .build()
            )
            .addFunction(
                FunSpec.builder("getRouterService")
                    .addModifiers(KModifier.OVERRIDE)
                    .addStatement("return routerServiceMap")
                    .returns(mapClass)
                    .build()
            )
            .addFunction(
                FunSpec.builder("getRouterServiceImpl")
                    .addModifiers(KModifier.OVERRIDE)
                    .addStatement("return routerServiceImplMap")
                    .returns(mapDataClass)
                    .build()
            )
            .addType(companion)
        return FileSpec.builder(packageName, className)
            .addType(classBuilder.build())
            .build()
    }

    private fun generateRouterPathMapBlock(): CodeBlock {
        val builder = CodeBlock.Builder()
        routerPathMap.forEach { (k, v) ->
            builder.addStatement("""routerPathMap["$k"] = ${v}::class.java """)
        }
        return builder.build()
    }

    private fun generateRouterServiceMapBlock(): CodeBlock {
        val builder = CodeBlock.Builder()
        routerServiceMap.forEach { (k, v) ->
            builder.addStatement("""routerServiceMap["$k"] = ${v}::class.java """)
        }
        return builder.build()
    }

    private fun generateRouterServiceImplMapBlock(): CodeBlock {
        val builder = CodeBlock.Builder()
        routerServiceImplMap.forEach { (k, v) ->
            builder.addStatement("""routerServiceImplMap["$k"] = RouterServiceData(cls=${(v.className)}::class.java, singleton=${v.singleton}) """)
        }
        return builder.build()
    }
}